﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Threading;
using Microsoft.Web.Mvc;
using SurveyHost.Controllers;
using SurveyHost.Models;

namespace SurveyHost.Support
{
    public static class HtmlHelperExtensions
    {
        // mock this in testing
#pragma warning disable 0649
        private static HttpContextBase _context;
#pragma warning restore 0649
        /// <summary>
        /// Use this context wrapper to access the current Context object
        /// </summary>
        private static HttpContextBase CurrentContext
        {
            get
            {
                return _context ?? new HttpContextWrapper(HttpContext.Current);
            }
        }
        /// <summary>
        /// Executes the contents of <paramref name="loggedIn"/> if the user is logged in, 
        /// <paramref name="notLoggedIn"/> if not.
        /// </summary>
        /// <param name="helper">The <seealso cref="HtmlHelper"/></param>
        /// <param name="notLoggedIn">An <seealso cref="Action"/> containing the markup to display when the user is not logged in</param>
        /// <param name="loggedIn">An <seealso cref="Action"/> containing the markup to display when the user is logged in</param>
        public static void LoginView(this HtmlHelper helper, Action notLoggedIn, Action loggedIn)
        {
            if (helper == null || notLoggedIn == null || loggedIn == null)
                throw new InvalidOperationException("You must supply the helper, notLoggedIn, and loggedIn arguments.");
            if (CurrentContext.Request.IsAuthenticated)
            {
                loggedIn();
            }
            else
            {
                notLoggedIn();
            }
        }
        /// <summary>
        /// Renders a security trimmed menu
        /// </summary>
        /// <param name="helper">The <seealso cref="HtmlHelper"/></param>
        /// <param name="template">An <seealso cref="Action{T}">tempate</seealso> that accepts the menu item's html anchor link</param>
        /// <param name="items">One or more <seealso cref="MenuItem"/>s configured to generate each menu item's html anchor.</param>
        public static void SecurityTrimmedMenu(this HtmlHelper helper, Action<string> template, params StmItem[] items)
        {
            if (helper == null || template == null || items == null)
                throw new InvalidOperationException("You must supply the helper, template and items.");
            string url = null;
            foreach (var item in items)
            {
                url = item.Render(helper, CurrentContext);
                if (!url.IsNullOrEmpty())
                    template(url);
            }
        }

        /// <summary>
        /// Displays one view for admins, another for other users
        /// </summary>
        /// <param name="helper">The <seealso cref="HtmlHelper"/>.</param>
        /// <param name="admin">The admin view.</param>
        /// <param name="other">The other user type view.</param>
        public static void AdminView(this HtmlHelper helper, Action admin, Action other)
        {
            if (helper == null) throw new ArgumentNullException("helper");
            if (admin == null) throw new ArgumentNullException("admin");
            if (other == null) throw new ArgumentNullException("other");
            if (Admin())
            {
                admin();
            }
            else
            {
                other();
            }
        }

        /// <summary>
        /// Displays the template content if and only if the current user is a member of the Admin group
        /// </summary>
        /// <param name="helper">The <seealso cref="HtmlHelper"/>.</param>
        /// <param name="template">The template to display if the current user is a member of the Admin group.</param>
        public static void AdminView(this HtmlHelper helper, Action template)
        {
            if (helper == null) throw new ArgumentNullException("helper");
            if (template == null) throw new ArgumentNullException("template");
            if (Admin()) template();
        }

        /// <summary>
        /// Returns a specific paragraph, or a link to edit the paragraph if the current user is a member of the Admin group.
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="name">The paragraph name.</param>
        /// <param name="defaultText">The text to display if the paragraph does not yet exist.</param>
        /// <returns>The paragraph text, or a link containing the paragraph text that points to the edit </returns>
        public static string Paragraph(this HtmlHelper helper, string name, string defaultText)
        {
            if (helper == null) throw new ArgumentNullException("helper");
            if (name == null) throw new ArgumentNullException("name");
            if (defaultText == null) throw new ArgumentNullException("text");
            var p = SurveyHost.Models.Paragraph.Retrieve(name);
            if (p == null)
            {
                p = new Paragraph
                {
                    Locale = Thread.CurrentThread.CurrentCulture.ToString(),
                    Name = name,
                    Text = (defaultText.IsNullOrEmpty()) ? "This is the default paragraph text" : defaultText
                };
                SurveyHost.Models.Paragraph.Create(p);
            }
            if (Admin())
                return "<span id=\"{0}\" class=\"editInPlace\">{1}</span>".FormatMe(p.Name, p.Text.HtmlEncode());
            return p.Text.HtmlEncode();
        }

        /// <summary>
        /// Returns a specific paragraph, or a link to edit the paragraph if the current user is a member of the Admin group.
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="name">The name of the paragraph.</param>
        /// <returns>The paragraph text, or a link containing the paragraph text that points to the edit </returns>
        public static string Paragraph(this HtmlHelper helper, string name)
        {
            return Paragraph(helper, name, null);
        }

        private static bool Admin()
        {
            return CurrentContext.User.IsInRole("Admin");
        }
    }
}
